﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Library.Extensions.Expressions;

namespace Core.Queries
{
    /// <summary>
    /// Query class is used to implement the Query Object Pattern    
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Query<T> : IPageQuery
    {
        public Query()
        {
            PageSize = 0;
            PageNumber = 1;
            SortAscending = true;
        }

        public bool Count { get; set; }
        public int PageSize { get; set; }
        public int PageNumber { get; set; }
        public string SortColumn { get; set; }
        public bool SortAscending { get; set; }

        public bool PagingEnabled
        {
            get
            {
                return PageSize > 0;
            }
            set
            {
                if (value)
                {
                    if (PageSize == 0)
                        throw new Exception("PageSize should be set to a value grather than 0");
                }
                else
                    PageSize = 0;
            }
        }       

        public virtual Expression<Func<T, bool>> ToExpression()
        {            
            return x => true;
        }
    }

    public static class QueryExtension
    {
        public static IQueryable<T> Query<T>(this IQueryable<T> set, Query<T> query)
        {            
            if (query.PagingEnabled && string.IsNullOrEmpty(query.SortColumn))
                throw new Exception("PagingEnabled enabled but SortColumn not defined");

            IQueryable<T> q = set.Where(query.ToExpression());

            if (query.PagingEnabled && !string.IsNullOrEmpty(query.SortColumn))
            {                
                if (query.SortAscending)
                    q = q.OrderBy(query.SortColumn);
                else
                    q = q.OrderByDescending(query.SortColumn);

                q = q.Skip((query.PageNumber - 1) * query.PageSize).Take(query.PageSize);                                    
            }            
         
            return q;
        }

        public static IQueryable<T> Where<T>(this IQueryable<T> set, Query<T> query)
        {
            return set.Where(query.ToExpression());
        }
    }
}